import { ElMessage, ElLoading, ElNotification } from 'element-plus'
import { getToken, removeToken, removeUser } from '@/app/storage'
import { LOGIN_NAME } from '@/const/router'
import router from '@/router'
import axios from 'axios'

/**
 * @description: axios请求
 * @param {object} option 请求配置
 * @param {string} option.url 请求地址
 * @param {string} option.method 请求方式
 * @param {object} option.data 请求参数
 * @param {object} option.headers 请求头
 * @param {boolean} option.loading 是否显示加载动画
 * @param {boolean} option.lock 是否锁定屏幕
 * @param {string} option.loadingText 加载动画文字
 * @param {string} option.background 加载动画背景颜色
 * @param {boolean} option.error 是否显示错误提示
 * @param {boolean} option.success 是否显示成功提示
 * @return {*}
 */
axios.defaults.withCredentials = true
const instance = axios.create({
  baseURL:
    import.meta.env.MODE === 'development'
      ? '/api'
      : 'https://mock.presstime.cn/mock/67282170caf0b4e52f14102d/api',
  timeout: 80000,
})
const LOGIN_LOSE_EFFICACY_TEXT = '登录状态失效，请重新登录'
let lodInstance = null

// 请求拦截
instance.interceptors.request.use(
  (config) => {
    const token = getToken()
    if (!token) {
      ElMessage.warning(LOGIN_LOSE_EFFICACY_TEXT)
      removeToken()
      removeUser()
      setTimeout(() => router.replace(`/${LOGIN_NAME}`), 500)
      return Promise.reject(new Error(LOGIN_LOSE_EFFICACY_TEXT))
    }
    // TODO: 指定target时，每次返回的都是单独的实例，需在service前进行关闭：lodInstance && lodInstance.close()
    const options = config?.options || {}
    const {
      lock = true,
      loading = true,
      loadingText = '加载中...',
      background = 'rgba(0, 0, 0, 0.5)',
    } = options
    loading &&
      (lodInstance = ElLoading.service({
        lock,
        text: loadingText,
        background,
      }))

    if (token) {
      config.headers.token = token
    }

    return config
  },
  (error) => Promise.reject(error),
)

// 响应拦截
instance.interceptors.response.use(
  (res) => {
    const {
      data: { data },
      config: { options },
    } = res
    hideLoading()

    if ([403, 401].includes(+data.code)) {
      ElMessage.warning(LOGIN_LOSE_EFFICACY_TEXT)
      removeToken()
      removeUser()
      setTimeout(() => router.replace(`/${LOGIN_NAME}`), 500)
      return Promise.reject(data.message || LOGIN_LOSE_EFFICACY_TEXT)
    }

    if (+res.status !== 200) {
      ElMessage.error(data.message || options?.errorText)
      return Promise.reject(data.message || options?.errorText)
    }

    options?.successText &&
      ElMessage.success(data.message || options?.successText)
    return data
  },
  (error) => {
    const ERROR_CODES_MAP = {
      400: '请求错误',
      401: '未授权，请登录',
      403: '拒绝访问',
      404: '请求地址不存在',
      500: '服务器繁忙',
      502: '网关错误',
      503: '服务不可用，服务器暂时过载或维护',
      504: '网关超时',
    }
    hideLoading()
    ElNotification.error({
      title: '请求错误',
      message: !error.response
        ? '网络连接异常'
        : ERROR_CODES_MAP[error.response.status],
    })
    return Promise.reject(new Error('请求错误'))
  },
)

function hideLoading() {
  const timer = setTimeout(() => {
    lodInstance && lodInstance.close()
    clearTimeout(timer)
  }, 500)
}

export default instance
